package rtsp;

import org.omg.PortableInterceptor.SYSTEM_EXCEPTION;

import java.io.IOException;
import java.net.*;
import java.util.Set;

public class UDPRetransmitter{
    private DatagramSocket client;
    private DatagramSocket server;
    private int originPlayerPort;
    private int rtspServerPort;
    private String originPlayerIp;
    private String rtspServerIp;
    private String type;

    private Thread sendThread;
    private Thread receiveThread;

    public UDPRetransmitter(DatagramSocket client, DatagramSocket server, int originPlayerPort, int rtspServerPort, String originPlayerIp, String rtspServerIp, String type) {
        this.client = client;
        this.server = server;
        this.originPlayerPort = originPlayerPort;
        this.rtspServerPort = rtspServerPort;
        this.originPlayerIp = originPlayerIp;
        this.rtspServerIp = rtspServerIp;
        this.type = type;
    }

    //这里的ServerPorts指的是转发程序监听播放器的服务端端口，clientPorts指的是连接到目标RTSP服务器的客户端端口
    public static void udpRetransmitterCreator(
            String reTranClientPorts,
            String reTranServerPorts,
            String rtspServerPorts,
            String originPlayerPorts,
            String rtspServerIp,
            String originPlayerIp,
            Set<UDPRetransmitter> set) throws SocketException, UnknownHostException {
        int rtpClientPort = Integer.parseInt(reTranClientPorts.substring(0, reTranClientPorts.indexOf("-")));
        int rtcpClientPort = Integer.parseInt(reTranClientPorts.substring(reTranClientPorts.indexOf("-") + 1));
        int rtpServerPort = Integer.parseInt(reTranServerPorts.substring(0, reTranServerPorts.indexOf("-")));
        int rtcpServerPort = Integer.parseInt(reTranServerPorts.substring(reTranServerPorts.indexOf("-") + 1));

        int rtspServerRTPort = Integer.parseInt(rtspServerPorts.substring(0, rtspServerPorts.indexOf("-")));
        int rtspServerRTCPPort = Integer.parseInt(rtspServerPorts.substring(rtspServerPorts.indexOf("-") + 1));
        int originPlayerRTPPort = Integer.parseInt(originPlayerPorts.substring(0, originPlayerPorts.indexOf("-")));
        int originPlayerRTCPPort = Integer.parseInt(originPlayerPorts.substring(originPlayerPorts.indexOf("-") + 1));

        DatagramSocket rtpClient = new DatagramSocket(rtpClientPort, InetAddress.getByName(rtspServerIp));
        DatagramSocket rtcpClient = new DatagramSocket(rtcpClientPort, InetAddress.getByName(rtspServerIp));
        DatagramSocket rtpServer = new DatagramSocket(rtpServerPort);
        DatagramSocket rtcpServer = new DatagramSocket(rtcpServerPort);


        UDPRetransmitter rtpRetransmitter = new UDPRetransmitter(rtpClient, rtpServer, originPlayerRTPPort ,rtspServerRTCPPort, originPlayerIp, rtspServerIp, "RTP");
        UDPRetransmitter rtcpRetransmitter = new UDPRetransmitter(rtcpClient, rtcpServer, originPlayerRTCPPort , rtspServerRTCPPort, originPlayerIp, rtspServerIp, "RTCP");

        rtcpRetransmitter.startRetransmit();
        rtpRetransmitter.startRetransmit();

        set.add(rtcpRetransmitter);
        set.add(rtpRetransmitter);
    }

    public void startRetransmit(){
        sendThread = new Thread(new SimpleUDPChannel(client, server, rtspServerPort, rtspServerIp, type));
        receiveThread = new Thread(new SimpleUDPChannel(server, client, originPlayerPort, originPlayerIp, type));

        sendThread.start();
        receiveThread.start();
    }

    public void endRetransmit(){
        sendThread.interrupt();
        receiveThread.interrupt();

        client.close();
        server.close();
    }

    private class SimpleUDPChannel implements Runnable{
        DatagramSocket receiver;
        DatagramSocket sender;
        int toPort;
        String toIp;
        String type;

        public SimpleUDPChannel(DatagramSocket sender, DatagramSocket receiver, int toPort, String toIp, String type){
            this.sender = sender;
            this.receiver = receiver;
            this.toPort = toPort;
            this.toIp = toIp;
            this.type = type;
        }

        @Override
        public void run() {
            DatagramPacket datagramPacket = new DatagramPacket(new byte[4096], 4096);
            try{
                while(!Thread.currentThread().isInterrupted()){
                    receiver.receive(datagramPacket);
                    datagramPacket.setAddress(InetAddress.getByName(this.toIp));
                    datagramPacket.setPort(this.toPort);
                    sender.send(datagramPacket);
                }
            }catch (IOException e){
                System.out.println("UDPChannel,Type:" + type + " ,targetAddress:" + toIp + ":" + toPort + " Caught IOException:" + e.getMessage());
                e.printStackTrace();
            }

        }
    }
}
